/******************************************************************************* * Copyright (c) 2009, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation ******************************************************************************/ package org.eclipse.ui.internal.statushandlers; import com.ibm.icu.text.DateFormat; import java.net.URL; import java.util.Collection; import java.util.Date; import java.util.Map; import org.eclipse.core.runtime.Adapters; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.resource.LocalResourceManager; import org.eclipse.jface.resource.ResourceManager; import org.eclipse.jface.viewers.ILabelDecorator; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.internal.WorkbenchMessages; import org.eclipse.ui.internal.progress.ProgressManager; import org.eclipse.ui.internal.progress.ProgressMessages; import org.eclipse.ui.progress.IProgressConstants; import org.eclipse.ui.statushandlers.IStatusAdapterConstants; import org.eclipse.ui.statushandlers.StatusAdapter; /** * This is an utility class which is responsible for text and icon decorators in * the StatusDialog. * * @since 3.6 */ public class LabelProviderWrapper extends ViewerComparator implements ITableLabelProvider { /** * The default status label provider. */ private class DefaultLabelProvider implements ITableLabelProvider { ResourceManager manager = new LocalResourceManager(JFaceResources .getResources()); @Override public void addListener(ILabelProviderListener listener) { // Do nothing } @Override public void dispose() { manager.dispose(); } @Override public Image getColumnImage(Object element, int columnIndex) { Image result = null; if (element != null) { StatusAdapter statusAdapter = ((StatusAdapter) element); Job job = Adapters.adapt(statusAdapter, Job.class); if (job != null) { result = getIcon(job); } } // if somehow disposed image was received (should not happen) if (result != null && result.isDisposed()) { result = null; } return result; } @Override public String getColumnText(Object element, int columnIndex) { StatusAdapter statusAdapter = (StatusAdapter) element; String text = WorkbenchMessages.WorkbenchStatusDialog_ProblemOccurred; if (!isMulti()) { Job job = Adapters.adapt(statusAdapter, Job.class); if (job != null) { text = getPrimaryMessage(statusAdapter); } else { text = getSecondaryMessage(statusAdapter); } } else { Job job = Adapters.adapt(statusAdapter, Job.class); if (job != null) { text = job.getName(); } else { text = getPrimaryMessage(statusAdapter); } } Long timestamp = (Long) statusAdapter .getProperty(IStatusAdapterConstants.TIMESTAMP_PROPERTY); if (timestamp != null && isMulti()) { String date = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG) .format(new Date(timestamp.longValue())); return NLS.bind(ProgressMessages.JobInfo_Error, (new Object[] { text, date })); } return text; } /* * Get the icon for the job. */ private Image getIcon(Job job) { if (job != null) { Object property = job .getProperty(IProgressConstants.ICON_PROPERTY); // Create an image from the job's icon property or family if (property instanceof ImageDescriptor) { return manager.createImage((ImageDescriptor) property); } else if (property instanceof URL) { return manager.createImage(ImageDescriptor .createFromURL((URL) property)); } else { // Let the progress manager handle the resource management return ProgressManager.getInstance().getIconFor(job); } } return null; } @Override public boolean isLabelProperty(Object element, String property) { return false; } @Override public void removeListener(ILabelProviderListener listener) { // Do nothing } } private ITableLabelProvider labelProvider; /** * This field stores the decorator which can override various texts produced * by this class. */ private ILabelDecorator messageDecorator; private Map dialogState; /** * @param dialogState */ public LabelProviderWrapper(Map dialogState) { this.dialogState = dialogState; } @Override public Image getColumnImage(Object element, int columnIndex) { return labelProvider.getColumnImage(element, columnIndex); } @Override public String getColumnText(Object element, int columnIndex) { return getLabelProvider().getColumnText(element, columnIndex); } @Override public void addListener(ILabelProviderListener listener) { getLabelProvider().addListener(listener); } /** * This method disposes the label provider if and only if the dialog is not * changing its state. * * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose() */ @Override public void dispose() { boolean modalitySwitch = ((Boolean) dialogState.get(IStatusDialogConstants.MODALITY_SWITCH)) .booleanValue(); if (!modalitySwitch) { getLabelProvider().dispose(); } } @Override public boolean isLabelProperty(Object element, String property) { return getLabelProvider().isLabelProperty(element, property); } @Override public void removeListener(ILabelProviderListener listener) { getLabelProvider().removeListener(listener); } /** * Gets {@link Image} associated with current {@link StatusAdapter} * severity. * * @param statusAdapter * * @return {@link Image} associated with current {@link StatusAdapter} * severity. */ public Image getImage(StatusAdapter statusAdapter) { if (statusAdapter != null) { int severity = statusAdapter.getStatus().getSeverity(); switch (severity) { case IStatus.OK: case IStatus.INFO: case IStatus.CANCEL: return getSWTImage(SWT.ICON_INFORMATION); case IStatus.WARNING: return getSWTImage(SWT.ICON_WARNING); default: /* IStatus.ERROR */ return getSWTImage(SWT.ICON_ERROR); } } // should not never happen but if we do not know what is going on, then // return error image. return getSWTImage(SWT.ICON_ERROR); } /** * Get an <code>Image</code> from the provide SWT image constant. * * @param imageID * the SWT image constant * @return image the image */ public Image getSWTImage(final int imageID) { return Display.getCurrent().getSystemImage(imageID); } /** * This method computes the dialog main message. * * If there is only one reported status adapter, main message should be: * <ul> * <li>information about job that reported an error.</li> * <li>primary message, if the statusAdapter was not reported by job</li> * </ul> * * If there is more reported statusAdapters, main message should be: * <ul> * <li>primary message for job reported statusAdapters</li> * <li>secondary message for statuses not reported by jobs</li> * </ul> * * If nothing can be found, some general information should be displayed. * * @param statusAdapter * A status adapter which is used as the base for computation. * @return main message of the dialog. * * @see #getPrimaryMessage(StatusAdapter) * @see #getSecondaryMessage(StatusAdapter) */ public String getMainMessage(StatusAdapter statusAdapter) { if (!isMulti()) { Job job = Adapters.adapt(statusAdapter, Job.class); // job if (job != null) { return NLS .bind( WorkbenchMessages.WorkbenchStatusDialog_ProblemOccurredInJob, job.getName()); } // we are not handling job return getPrimaryMessage(statusAdapter); } // we have a list. primary message or job name or on the list name (both // with timestamp if available). // we display secondary message or status if (isMulti()) { Job job = Adapters.adapt(statusAdapter, Job.class); // job if (job != null) { return getPrimaryMessage(statusAdapter); } // plain status return getSecondaryMessage(statusAdapter); } return WorkbenchMessages.WorkbenchStatusDialog_ProblemOccurred; } /** * Retrieves primary message from passed statusAdapter. Primary message * should be (from the most important): * <ul> * <li>statusAdapter title</li> * <li>IStatus message</li> * <li>pointing to child statuses if IStatus has them.</li> * <li>exception message</li> * <li>exception class</li> * <li>general message informing about error (no details at all)</li> * </ul> * * @param statusAdapter * an status adapter to retrieve primary message from * @return String containing primary message * * @see #getMainMessage(StatusAdapter) * @see #getSecondaryMessage(StatusAdapter) */ public String getPrimaryMessage(StatusAdapter statusAdapter) { // if there was nonempty title set, display the title Object property = statusAdapter .getProperty(IStatusAdapterConstants.TITLE_PROPERTY); if (property instanceof String) { String header = (String) property; if (header.trim().length() > 0) { return decorate(header, statusAdapter); } } // if there was message set in the status IStatus status = statusAdapter.getStatus(); if (status.getMessage() != null && status.getMessage().trim().length() > 0) { return decorate(status.getMessage(), statusAdapter); } // if status has children if (status.getChildren().length > 0) { return WorkbenchMessages.WorkbenchStatusDialog_StatusWithChildren; } // check the exception Throwable t = status.getException(); if (t != null) { if (t.getMessage() != null && t.getMessage().trim().length() > 0) { return decorate(t.getMessage(), statusAdapter); } return t.getClass().getName(); } return WorkbenchMessages.WorkbenchStatusDialog_ProblemOccurred; } /** * Retrieves secondary message from the passed statusAdapter. Secondary * message is one level lower than primary. Secondary message should be * (from the most important): * <ul> * <li>IStatus message</li> * <li>pointing to child statuses if IStatus has them.</li> * <li>exception message</li> * <li>exception class</li> * </ul> * Secondary message should not be the same as primary one. If no secondary * message can be extracted, details should be pointed. * * @param statusAdapter * an status adapter to retrieve secondary message from * @return String containing secondary message * * @see #getMainMessage(StatusAdapter) * @see #getPrimaryMessage(StatusAdapter) */ public String getSecondaryMessage(StatusAdapter statusAdapter) { String primary = getPrimaryMessage(statusAdapter); // we can skip the title, it is always displayed as primary message // if there was message set in the status IStatus status = statusAdapter.getStatus(); String message = status.getMessage(); String decoratedMessage = message == null ? null : decorate(message, statusAdapter); if (message != null && message.trim().length() > 0 && !primary.equals(decoratedMessage)) { /* we have not displayed it yet */ return decoratedMessage; } // if status has children if (status.getChildren().length > 0 && !primary.equals(decoratedMessage)) { return WorkbenchMessages.WorkbenchStatusDialog_StatusWithChildren; } // check the exception Throwable t = status.getException(); if (t != null) { if (t.getMessage() != null) { String decoratedThrowable = decorate(t.getMessage(), statusAdapter); if (t.getMessage().trim().length() > 0 && !primary.equals(decoratedThrowable)) { return decoratedThrowable; } } String throwableName = t.getClass().getName(); if (!primary.equals(throwableName)) { return throwableName; } } return WorkbenchMessages.WorkbenchStatusDialog_SeeDetails; } private String decorate(String string, StatusAdapter adapter) { messageDecorator = (ILabelDecorator) dialogState .get(IStatusDialogConstants.DECORATOR); if (messageDecorator != null) { string = messageDecorator.decorateText(string, adapter); } return string; } private int compare(StatusAdapter s1, StatusAdapter s2) { Long timestamp1 = ((Long) s1 .getProperty(IStatusAdapterConstants.TIMESTAMP_PROPERTY)); Long timestamp2 = ((Long) s2 .getProperty(IStatusAdapterConstants.TIMESTAMP_PROPERTY)); if (timestamp1 == null || timestamp2 == null || (timestamp1.equals(timestamp2))) { String text1 = getColumnText(s1, 0); String text2 = getColumnText(s2, 0); return text1.compareTo(text2); } if (timestamp1.longValue() < timestamp2.longValue()) { return -1; } if (timestamp1.longValue() > timestamp2.longValue()) { return 1; } // should be never called return 0; } @Override public int compare(Viewer testViewer, Object o1, Object o2) { if (o1 instanceof StatusAdapter && o2 instanceof StatusAdapter) { return compare((StatusAdapter) o1, (StatusAdapter) o2); } // should not happen if (o1.hashCode() < o2.hashCode()) { return -1; } if (o2.hashCode() > o2.hashCode()) { return 1; } return 0; } private boolean isMulti() { return ((Collection) dialogState .get(IStatusDialogConstants.STATUS_ADAPTERS)).size() > 1; } /** * @return Returns the labelProvider. */ public ITableLabelProvider getLabelProvider() { ITableLabelProvider temp = (ITableLabelProvider) dialogState .get(IStatusDialogConstants.CUSTOM_LABEL_PROVIDER); if (temp != null) { labelProvider = temp; } if (labelProvider == null) { labelProvider = new DefaultLabelProvider(); } return labelProvider; } }